package ru.gitverse.deenyy.walp.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.gitverse.deenyy.walp.model.*;
import ru.gitverse.deenyy.walp.repository.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Optional;
import java.util.Random;

@Service
public class AngleService {
    @Autowired
    private AngleRepository angleRepository;

    @Autowired
    private KLKRResultRepository klkrResultRepository;

    @Autowired
    private GammaResultRepository gammaResultRepository;

    @Autowired
    private DeltaGammaResultRepository deltaGammaResultRepository;

    private BigDecimal AG5; // AG9 на нулевой высоте, константа для всех высот

    public CalculationResult calculateAndSaveAngles(Angle angle1, Angle angle2) {
        // Сохраняем Angle
        angleRepository.save(angle1);
        angleRepository.save(angle2);

        // Получаем значения из объектов Angle
        int degrees1 = angle1.getDegrees();
        int minutes1 = angle1.getMinutes();
        int seconds1 = angle1.getSeconds();

        int degrees2 = angle2.getDegrees();
        int minutes2 = angle2.getMinutes();
        int seconds2 = angle2.getSeconds();

        // Переводим в градусы с использованием BigDecimal
        BigDecimal V9 = BigDecimal.valueOf(degrees1)
                .add(BigDecimal.valueOf(minutes1).divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_UP))
                .add(BigDecimal.valueOf(seconds1).divide(BigDecimal.valueOf(3600), 6, RoundingMode.HALF_UP));
        BigDecimal V10 = BigDecimal.valueOf(degrees2)
                .add(BigDecimal.valueOf(minutes2).divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_UP))
                .add(BigDecimal.valueOf(seconds2).divide(BigDecimal.valueOf(3600), 6, RoundingMode.HALF_UP));

        // Сравнение
        BigDecimal W9 = V9.equals(BigDecimal.ZERO) ? V9.subtract(V10) : V9.subtract(V10).add(BigDecimal.valueOf(180));

        // Вычисление KL-KR
        int X9 = truncate(W9);
        BigDecimal X10 = W9.subtract(BigDecimal.valueOf(X9)).multiply(BigDecimal.valueOf(60));
        int Y9 = truncate(X10);
        BigDecimal Y10 = X10.subtract(BigDecimal.valueOf(Y9));
        BigDecimal Z9 = (Y10.multiply(BigDecimal.valueOf(60)).setScale(0, RoundingMode.FLOOR).add(BigDecimal.ONE).compareTo(BigDecimal.valueOf(60)) == 0) ? BigDecimal.valueOf(60) : Y10.multiply(BigDecimal.valueOf(60));
        BigDecimal Z10 = Z9.equals(BigDecimal.valueOf(60)) ? X10 : Z9;

        KLKRResult klkrResult = new KLKRResult();
        klkrResult.setDegrees(X9);
        klkrResult.setMinutes(Z9.equals(BigDecimal.valueOf(60)) ? Y9 + 1 : Y9);
        klkrResult.setSeconds(Z9.equals(BigDecimal.valueOf(60)) ? 0 : Z9.setScale(0, RoundingMode.HALF_UP).intValue()); //не ОТБР а ОКРУГЛ

        klkrResultRepository.save(klkrResult);

        // Расчет βср для левого пояса
        BigDecimal AA9 = V9;
        BigDecimal AA10 = V10;
        BigDecimal AB9L = V9.equals(BigDecimal.ZERO) ? (AA9.add(AA10)).divide(BigDecimal.valueOf(2), 6, RoundingMode.HALF_UP) : (AA9.add(AA10).subtract(BigDecimal.valueOf(180))).divide(BigDecimal.valueOf(2), 6, RoundingMode.HALF_UP);

        int AC9 = truncate(AB9L);
        BigDecimal AC10 = AB9L.subtract(BigDecimal.valueOf(AC9)).multiply(BigDecimal.valueOf(60));
        int AD9 = truncate(AC10);
        BigDecimal AD10 = AC10.subtract(BigDecimal.valueOf(AD9));
        BigDecimal AE9 = (AD10.multiply(BigDecimal.valueOf(60)).setScale(0, RoundingMode.FLOOR).add(BigDecimal.ONE).compareTo(BigDecimal.valueOf(60)) == 0) ? BigDecimal.valueOf(60) : AD10.multiply(BigDecimal.valueOf(60));
        BigDecimal AE10 = AE9.equals(BigDecimal.valueOf(60)) ? AC10 : AE9;

        KLKRResult betaResult = new KLKRResult();
        betaResult.setDegrees(AC9);
        betaResult.setMinutes(AE9.equals(BigDecimal.valueOf(60)) ? AD9 + 1 : AD9);
        betaResult.setSeconds(AE9.equals(BigDecimal.valueOf(60)) ? 0 : AE9.setScale(0, RoundingMode.HALF_UP).intValue()); //не ОТБР а ОКРУГЛ

        klkrResultRepository.save(betaResult);

        return new CalculationResult(klkrResult, betaResult);
    }

    public GammaCalculationResult calculateAndSaveGamma(Angle leftAngleKL, Angle leftAngleKR, Angle rightAngleKL, Angle rightAngleKR) {
        // Рассчитываем первое измерение
        CalculationResult leftMeasurement;
        leftMeasurement = calculateAndSaveAngles(leftAngleKL, leftAngleKR);
        BigDecimal AB9L = new BigDecimal(leftMeasurement.getBetaResult().getDegrees())
                .add(BigDecimal.valueOf(leftMeasurement.getBetaResult().getMinutes()).divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_UP))
                .add(BigDecimal.valueOf(leftMeasurement.getBetaResult().getSeconds()).divide(BigDecimal.valueOf(3600), 6, RoundingMode.HALF_UP));

        // Рассчитываем второе измерение
        CalculationResult rightMeasurement;
        rightMeasurement = calculateAndSaveAngles(rightAngleKL, rightAngleKR);
        BigDecimal AB9R = new BigDecimal(rightMeasurement.getBetaResult().getDegrees())
                .add(BigDecimal.valueOf(rightMeasurement.getBetaResult().getMinutes()).divide(BigDecimal.valueOf(60), 6, RoundingMode.HALF_UP))
                .add(BigDecimal.valueOf(rightMeasurement.getBetaResult().getSeconds()).divide(BigDecimal.valueOf(3600), 6, RoundingMode.HALF_UP));

        // Расчет gamma
        BigDecimal AF9 = AB9L;
        BigDecimal AF10 = AB9R;
        BigDecimal AG9 = (AF9.add(AF10)).divide(BigDecimal.valueOf(2), 6, RoundingMode.HALF_UP);

        int AH9 = truncate(AG9);
        BigDecimal AH10 = AG9.subtract(BigDecimal.valueOf(AH9)).multiply(BigDecimal.valueOf(60));
        int AI9 = truncate(AH10);
        BigDecimal AI10 = AH10.subtract(BigDecimal.valueOf(AI9));
        BigDecimal AJ9 = (AI10.multiply(BigDecimal.valueOf(60)).setScale(0, RoundingMode.FLOOR).add(BigDecimal.ONE).compareTo(BigDecimal.valueOf(60)) == 0) ? BigDecimal.valueOf(60) : AI10.multiply(BigDecimal.valueOf(60));
        BigDecimal AJ10 = AJ9.equals(BigDecimal.valueOf(60)) ? AH10 : AJ9;

        GammaResult gammaResult = new GammaResult();
        gammaResult.setDegrees(AH9);
        gammaResult.setMinutes(AJ9.equals(BigDecimal.valueOf(60)) ? AI9 + 1 : AI9);
        gammaResult.setSeconds(AJ9.equals(BigDecimal.valueOf(60)) ? 0 : AJ9.setScale(0, RoundingMode.HALF_UP).intValue()); //не ОТБР а ОКРУГЛ

        gammaResultRepository.save(gammaResult);

        if (AG5 == null) {
            AG5 = AG9; // Устанавливаем AG5 на нулевой высоте
        }

        // Вычисляем и сохраняем deltaGamma
        DeltaGammaResult deltaGammaResult = calculateDeltaGamma(AG9);

        return new GammaCalculationResult(leftMeasurement, rightMeasurement, gammaResult, AG9, deltaGammaResult);
    }


    private DeltaGammaResult calculateDeltaGamma(BigDecimal AG9) {
        BigDecimal AK9 = AG9.equals(BigDecimal.ZERO) ? BigDecimal.ZERO : AG9.subtract(AG5);

        int AL9 = truncate(AK9);
        BigDecimal AL10 = AK9.subtract(BigDecimal.valueOf(AL9)).multiply(BigDecimal.valueOf(60));
        int AM9 = truncate(AL10);
        BigDecimal AM10 = AL10.subtract(BigDecimal.valueOf(AM9));

        BigDecimal AN9;
        if (AM10.compareTo(BigDecimal.ZERO) < 0) {
            AN9 = (AM10.multiply(BigDecimal.valueOf(60)).setScale(0, RoundingMode.FLOOR).subtract(BigDecimal.ONE).compareTo(BigDecimal.valueOf(-60)) == 0) ? BigDecimal.valueOf(-60) : AM10.multiply(BigDecimal.valueOf(60));
        } else {
            AN9 = (AM10.multiply(BigDecimal.valueOf(60)).setScale(0, RoundingMode.FLOOR).add(BigDecimal.ONE).compareTo(BigDecimal.valueOf(60)) == 0) ? BigDecimal.valueOf(60) : AM10.multiply(BigDecimal.valueOf(60));
        }

        DeltaGammaResult deltaGammaResult = new DeltaGammaResult();
        deltaGammaResult.setDegrees(AL9);
        deltaGammaResult.setMinutes(AN9.compareTo(BigDecimal.ZERO) < 0 ? (AN9.compareTo(BigDecimal.valueOf(-60)) == 0 ? AM9 - 1 : AM9) : (AN9.compareTo(BigDecimal.valueOf(60)) == 0 ? AM9 + 1 : AM9));
        deltaGammaResult.setSeconds(AN9.compareTo(BigDecimal.valueOf(60)) == 0 || AN9.compareTo(BigDecimal.valueOf(-60)) == 0 ? 0 : AN9.setScale(0, RoundingMode.HALF_UP).intValue()); //не ОТБР а ОКРУГЛ

        deltaGammaResultRepository.save(deltaGammaResult);

        return deltaGammaResult;
    }

    public static int truncate(BigDecimal number) {
        int intValue;
        if (number.compareTo(BigDecimal.ZERO) < 0) {
            intValue = number.setScale(0, RoundingMode.CEILING).intValue();
        } else {
            intValue = number.setScale(0, RoundingMode.FLOOR).intValue();
        }
        return intValue;
    }
}
